﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace POC.Configuration
{
    public enum MergeSettings
    {
        FirstOccurence = 1,
        LastOne = 2,
        Any = 3
    }   

    public static class ApplicationConfiguration
    {
       
        static Dictionary<string, IConfigReader> readers = new Dictionary<string, IConfigReader>();
        public static MergeSettings MergeSetting { set; private get; }
        //Dependency injection..
        //it should read the config from anywhere...then can merge it to given one
        static IDictionary<string, string> localVariables = null;

        public static IDictionary<string, string> LocalVariables
        {
            get
            {

                if (localVariables == null)
                {
                    localVariables = List();
                }

                return ApplicationConfiguration.localVariables;
            }
            set
            {
                lock (locker_one)
                {
                    ApplicationConfiguration.localVariables = value;
                }
            }
        }
        static string locker_one = "locker";
        static ApplicationConfiguration()
        {
            var reader = new AppConfigReader();
            MergeSetting = MergeSettings.LastOne;
            BindReader(reader, reader.GetType().Name);
        }
        public static void UnBindReader(IConfigReader ireader, string name = null)
        {
            if (string.IsNullOrEmpty(name))
            {
                readers.Remove(ireader.GetType().Name);
            }
            else
            {
                readers.Remove(name);
            }
        }
        public static void ReBindFileReader(string name = null)
        {
            string filePath = Get(ConfigKeyConstant.ConfigFile);
            string nodeName = Get(ConfigKeyConstant.NodeName);
            BindFileReader(filePath, nodeName, name);
        }
        public static void BindWebFileReader(string filePath, string nodeName, string name = null)
        {
            var applicationVirtualPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
            ApplicationConfiguration.BindFileReader(applicationVirtualPath + "\\" + filePath, nodeName);
        }
        public static void BindFileReader(string filePath, string nodeName, string name = null)
        {
            FileConfigReader ireader = new FileConfigReader(filePath, nodeName);
            string readertype = string.IsNullOrEmpty(name) ? ireader.GetType().Name : name;
            readers[readertype] = ireader;
            // try
            ireader.Reload();
            Set(ConfigKeyConstant.ConfigFile, filePath);
            Set(ConfigKeyConstant.NodeName, nodeName);
            Set(ConfigKeyConstant.ReaderType, readertype);
        }
        public static void BindReader(IConfigReader ireader, string name = null)
        {
            string readertype = string.IsNullOrEmpty(name) ? ireader.GetType().Name : name;
            readers[readertype] = ireader;

        }
        public static string Get(string key)
        {
            try
            {
                string val = LocalVariables.Get(key);
                if (string.IsNullOrEmpty(val))
                {
                    val = TryAllKey(key);
                }
                return val;
            }
            catch
            {
            }
            return string.Empty;
        }
        private static string TryAllKey(string key)
        {
            string val = null;
            foreach (var readerKey in readers.Keys)
            {
                try
                {
                    val = readers[readerKey].ReadNode(key, "");
                    if (val != null && (MergeSetting == MergeSettings.FirstOccurence
                                     || MergeSetting == MergeSettings.Any))
                    {
                        break;
                    }
                }
                catch
                {
                }
            }
            return val;
        }
        public static IDictionary<string, string> List()
        {
            IDictionary<string, string> blanks = new Dictionary<string, string>();
            foreach (var readerKey in readers.Keys)
            {
                try
                {
                    var moreItems = readers[readerKey].List();
                    blanks = blanks.Union(moreItems).ToDictionary(k => k.Key, v => v.Value);
                }
                catch
                {
                }
            }
            lock (locker_one)
            {
                if (localVariables == null)
                {
                    localVariables = new Dictionary<string, string>();
                }
                foreach (var kp in blanks)
                {
                    // Overwrite
                    localVariables[kp.Key] = kp.Value;
                }
            }
            return localVariables;
        }
        public static void Set(string key, string val)
        {
            // Special case Contains
            if (LocalVariables.Contains(key))
            {
                LocalVariables[key] = val;
            }
            else
            {
                LocalVariables.Add(key, val);
            }
        }
    }
}
